AWS Lambda の Function を iOS からアップロードする
UploadFunction
AWS Lambda には、Lambda Function をアップロードするための UploadFunction という API が用意されています。これは Zip ファイルに圧縮した Lambda Function のソースコードをアップロードすることができる便利な API です。
今回は、この UploadFunction を iOS アプリから呼んでみたいと思います。つまり、モバイルアプリから Lambda Function を自由に定義できるというおもしろ構成です。
AWS SDK for iOS に実装する
AWS SDK for iOS は Lambda API は現在未対応です。ですので、例によって Fork したリポジトリ内で自作実装しました。Lambda の UploadFunction API をいますぐ使いたい!という方は下記リポジトリをインポートしてください。
改修したコードを全て見せる必要もないので、重要なところだけ抜粋して紹介します。以下はリクエストのモデルのヘッダーです。
@interface AWSLambdaUploadFunctionRequest : AWSRequest @property (nonatomic, strong) NSString *functionDescription; @property (nonatomic, strong) NSString *functionName; @property (nonatomic, strong) NSString *handler; @property (nonatomic, strong) NSNumber *memorySize; @property (nonatomic, strong) NSString *mode; @property (nonatomic, strong) NSString *role; @property (nonatomic, strong) NSString *runtime; @property (nonatomic, strong) NSNumber *timeout; @property (nonatomic, strong) id functionZip; @end
一番下の functionZip は HTTPBody で、それ以外はクエリパラメータです。特に重要なのは Lambda Function に与えるメモリ容量である memorySize、タイムアウト時間である timeout です。これらは実行したい Lambda Function のパフォーマンスを考慮しながら設定する必要があります。
アップロードしてみる
ということでアップロードしてみます。下記はテストコードですが、実装時は BFTask の continueWithBlock: 以降を書き換えれば動作するはずです。予め、アップロードする Lambda Function のソースコードを圧縮した Zip ファイルを用意する必要があります。
- (void)testUploadFunction { AWSLambda *lambda = [AWSLambda defaultLambda]; AWSLambdaUploadFunctionRequest *request = [AWSLambdaUploadFunctionRequest new]; request.functionDescription = @"Uploaded by iOS"; request.functionName = @"SampleFunction"; request.handler = @"SampleFunction.handler"; request.memorySize = @256; request.mode = @"event"; request.role = @"arn:aws:iam::xxxxxxxxxxxx:role/lambda_exec_role"; request.runtime = @"nodejs"; request.timeout = @10; NSBundle *bundle = [NSBundle bundleForClass:[self class]]; NSString *path = [bundle pathForResource:@"lambda-function-input.js" ofType:@"zip"]; NSData *data = [[NSData alloc] initWithContentsOfFile:path]; request.functionZip = data; [[[lambda uploadFunction:request] continueWithBlock:^id(BFTask *task) { if (task.error) { XCTFail(@"Error: [%@]", task.error); } if (task.result) { XCTAssertTrue([task.result isKindOfClass:[AWSLambdaUploadFunctionResponse class]]); AWSLambdaUploadFunctionResponse *response = task.result; XCTAssertTrue([response.functionName isEqualToString:@"SampleFunction"]); } return nil; }] waitUntilFinished]; }
なお、UploadFunction では Lambda Function に IAM Role を付与する処理が入るため、UploadFunction をコールするクライアントの IAM Role (今回の場合、Cognito の IAM Role) に "iam:PassRole" の権限を与える必要があります。
{ "Version": "2012-10-17", "Statement": [{ "Action": [ "mobileanalytics:PutEvents", "cognito-sync:*", "lambda:*", "iam:PassRole" ], "Effect": "Allow", "Resource": [ "*" ] }] }
テストを実行後、Management Console を見てみると正しくアップロードできていることが確認できます。
まとめ
Lambda 登場後、Lambda Function は開発者が定義するものという認識が強かったですが、iOS アプリから作るというのは今までになかった新しい試みではないかと思っています。有用かどうかわ分かりませんがw
今後も Lambda を iOS から触って行きたいと思います。引き続き GitHub のリポジトリは更新していく予定ですので、ぜひチェックしていただければと思います。